#!/usr/bin/env python

import unittest

from kumon import LiveCell, DeadCell, MainBoard


class TestLiveCell(unittest.TestCase):

    def test_new(self):
        c = LiveCell()
        self.assertFalse(c.dead)

    def test_evolve(self):
        c = LiveCell()
        self.assertTrue(c.evolve().dead)
        self.assertTrue(c.evolve([LiveCell()]).dead)
        self.assertTrue(c.evolve([LiveCell()] * 4).dead)
        self.assertTrue(c.evolve([LiveCell()] * 9).dead)
        self.assertTrue(c.evolve([DeadCell()] * 9).dead)
        self.assertFalse(c.evolve([LiveCell()] * 2).dead)
        self.assertFalse(c.evolve([LiveCell()] * 3).dead)

    def test_dna(self):
        c = LiveCell()
        self.assertNotEqual(c.dna, None)

        c = LiveCell(dna='a')
        self.assertEqual(c.dna, 'a')

        self.assertEqual(c.evolve([LiveCell(dna='a')] * 3).dna, 'a')
        self.assertEqual(c.evolve([LiveCell(dna='x'), LiveCell(dna='y')]).dna, 'a')


class TestDeadCell(unittest.TestCase):

    def test_new(self):
        c = DeadCell()
        self.assertTrue(c.dead)

    def test_evolve(self):
        c = DeadCell()
        self.assertTrue(c.evolve().dead)
        self.assertTrue(c.evolve([LiveCell()] * 2).dead)
        self.assertTrue(c.evolve([LiveCell()] * 7).dead)
        self.assertTrue(c.evolve([LiveCell()] * 9).dead)
        self.assertFalse(c.evolve([LiveCell()] * 3).dead)
        self.assertFalse(c.evolve([LiveCell()] * 3 + [DeadCell()] * 5).dead)

    def test_dna(self):
        d = DeadCell()
        c = d.evolve([LiveCell(dna='a')] * 3)
        assert(not c.dead)
        self.assertEqual(c.dna, 'a')

        d = DeadCell()
        c = d.evolve([LiveCell(dna='a'), LiveCell(dna='b'), LiveCell(dna='c')])
        assert(not c.dead)
        self.assertIn(c.dna, ['a', 'b', 'c'])


class TestBoard(unittest.TestCase):

    def test_new(self):
        b = MainBoard()
        self.assertEqual(b.height, 16)
        self.assertEqual(b.width, 64)
        self.assertEqual(len(b.cells), 64)
        self.assertEqual(len(b.cells[0]), 16)
        self.assertEqual(len(list(b.all_cells)), 1024)
        self.assertTrue(all(x.dead for x in b.all_cells))

        b = MainBoard(8, 8, LiveCell)
        self.assertEqual(b.height, 8)
        self.assertEqual(b.width, 8)
        self.assertEqual(len(b.cells), 8)
        self.assertEqual(len(b.cells[0]), 8)
        self.assertEqual(len(list(b.all_cells)), 64)
        self.assertTrue(all(not x.dead for x in b.all_cells))

    def test_neighbours(self):
        b = MainBoard()
        assert(b.width == 64)
        assert(b.height == 16)
        self.assertItemsEqual(b.get_neighbours_locs(2, 2), [(1, 1), (1, 2), (1, 3),
                                                            (2, 1), (2, 3),
                                                            (3, 1), (3, 2), (3, 3)])
        self.assertItemsEqual(b.get_neighbours_locs(0, 0), [(0, 1), (1, 0), (1, 1)])
        self.assertItemsEqual(b.get_neighbours_locs(63, 0), [(62, 0), (62, 1), (63, 1)])
        self.assertItemsEqual(b.get_neighbours_locs(0, 15), [(0, 14), (1, 14), (1, 15)])
        self.assertItemsEqual(b.get_neighbours_locs(63, 15), [(62, 14), (62, 15), (63, 14)])
        self.assertItemsEqual(b.get_neighbours_locs(42, 0), [(41, 0), (43, 0),
                                                             (41, 1), (42, 1), (43, 1)])

        assert(all(x.dead for x in b.all_cells))
        self.assertTrue(all(x.dead for x in b.get_neighbours(2, 2)))
        self.assertEqual(len(b.get_neighbours(2, 2)), 8)
                
    def test_dead_board(self):
        b = MainBoard()
        assert(all(x.dead for x in b.all_cells))
        b.evolve()
        self.assertTrue(b.all_dead)
        b.evolve(20)
        self.assertTrue(b.all_dead)

    def test_one_live(self):
        b = MainBoard()
        b.cells[2][2] = LiveCell()
        assert(not b.cells[2][2].dead)
        b.evolve()
        self.assertTrue(b.all_dead)

    def test_inmortal(self):
        b = MainBoard()
        for x in range(2, 4):
            for y in range(2, 4):
                b.cells[x][y] = LiveCell()

        assert(not b.all_dead)
        b.evolve()
        self.assertFalse(b.all_dead)
        b.evolve(30)
        self.assertFalse(b.all_dead)

    def test_populate(self):
        b = MainBoard()
        assert(b.all_dead)
        b.populate([LiveCell])
        self.assertFalse(b.all_dead)

    def test_dumps(self):
        b = MainBoard(width=3, height=3)
        assert(b.all_dead)
        self.assertEqual(b.dumps(), '...\n...\n...')

        b.cells[0][0] = LiveCell(dna='a')
        b.cells[1][1] = LiveCell(dna='x')
        b.cells[2][2] = LiveCell(dna='z')
        self.assertEqual(b.dumps(), 'a..\n.x.\n..z')

    def test_loads(self):
        b = MainBoard(width=3, height=3)
        b.loads('a..\n.x.\n..z')
        self.assertEqual(b.cells[0][0].dna, 'a')
        self.assertEqual(b.cells[1][1].dna, 'x')
        self.assertEqual(b.cells[2][2].dna, 'z')
        self.assertTrue(all(b.cells[x[0]][x[1]].dead for x in ((0, 1), (0, 2), (1, 0),
                                                               (1, 2), (2, 0), (2, 1))))
        b.loads('....\n....', set_size=True)
        self.assertEqual(b.width, 4)
        self.assertEqual(b.height, 2)
        self.assertTrue(b.all_dead)


if __name__ == '__main__':
    unittest.main()
